package cn.funeralobjects.utils;

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 网络工具类
 *
 * @author FuneralObjects
 * Create date: 2020/11/29 12:15 AM
 */
public class NetworkUtils {

    private static final GetIp[] GET_IPS = {
            new GetIp().setUrl("https://trackip.net/ip").setExtractFun(str -> str.replaceFirst("%", "")),
            new GetIp().setUrl("https://api.ipify.org?format=text").setExtractFun(str -> str.replaceFirst("%", "")),
            new GetIp().setUrl("https://ifconfig.me").setExtractFun(str -> str.replaceFirst("%", ""))
    };

    private static final String IPV4_PATTERN = "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$";

    private static final Logger LOGGER = LoggerFactory.getLogger(NetworkUtils.class);

    @Data
    @Accessors(chain = true)
    private static class GetIp {
        private String url;
        private Function<String, String> extractFun;
    }

    /**
     * 获取公网IPv4
     *
     * @param logger 自定义日志对象
     * @return Ipv4
     */
    public static String getInternetIpv4(Logger logger) {
        return List.of(GET_IPS)
                .stream()
                .map(getIp -> {
                    try {
                        return getInternetIpv4(getIp.getUrl(), 30000L, getIp.getExtractFun());
                    } catch (IOException e) {
                        logger.warn("Get ip failed, from: " + getIp, e);
                        return null;
                    }
                }).filter(Objects::nonNull)
                .filter(ipv4 -> {
                    boolean isIpv4 = NetworkUtils.isIpv4(ipv4);
                    if (!isIpv4) {
                        logger.info("The ip {} is not ipv4, ignore it.", ipv4);
                    }
                    return isIpv4;
                }).findFirst().orElse(null);
    }

    /**
     * 获取公网IP
     *
     * @return Ipv4
     */
    public static String getInternetIpv4() {
        return getInternetIpv4(LOGGER);
    }


    /**
     * 从自定义地址获取ip
     *
     * @param ipCheckUrl ip获取地址
     * @param timeout    超时设置
     * @param extractIp  提取ip方法
     * @return ip值
     * @throws IOException 访问异常
     */
    public static String getInternetIpv4(String ipCheckUrl, Long timeout, Function<String, String> extractIp) throws IOException {
        HttpGet get = new HttpGet(ipCheckUrl);
        get.setConfig(RequestConfig.custom().setConnectTimeout(timeout.intValue()).setSocketTimeout(timeout.intValue()).setConnectionRequestTimeout(timeout.intValue()).build());
        HttpResponse response = HttpClientBuilder.create().build().execute(get);
        return extractIp.apply(new String(IOUtils.buffer(response.getEntity().getContent()).readAllBytes(), StandardCharsets.UTF_8));
    }

    /**
     * 判断是否为ipv4地址
     *
     * @param ip ip
     * @return true - 是
     */
    public static boolean isIpv4(String ip) {
        Pattern pattern = Pattern.compile(IPV4_PATTERN);
        Matcher matcher = pattern.matcher(ip);
        return matcher.find();
    }
}
